﻿
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using TomanuExtensions;
using System.Linq;

namespace TomanuExtensionsTest
{
    [TestClass]
    public class SingleExtensionsTest
    {
        [TestMethod]
        public void SingleExtensions_Test()
        {
            SingleExtensions_IsNumber();
            SingleExtensions_Fraction();
            SingleExtensions_Limit();
            SingleExtensions_InRange();
            SingleExtensions_MinMax();
        }

        private void SingleExtensions_MinMax()
        {
            float[] nums = new float[] { -3, -2.9f, -2, -1, -0.1f, 0, 0.1f, 1, 2, 2.9f, 3 };

            var triples = from n1 in nums
                          from n2 in nums
                          from n3 in nums
                          select new { n1, n2, n3 };

            foreach (var triple in triples)
            {
                float min1 = SingleExtensions.Min(triple.n1, triple.n2, triple.n3);
                float min2 = Math.Min(triple.n1, Math.Min(triple.n2, triple.n3));
                Assert.AreEqual(min2, min1);
            }

            foreach (var triple in triples)
            {
                float max1 = SingleExtensions.Max(triple.n1, triple.n2, triple.n3);
                float max2 = Math.Max(triple.n1, Math.Max(triple.n2, triple.n3));
                Assert.AreEqual(max2, max1);
            }

            var quads = from n1 in nums
                        from n2 in nums
                        from n3 in nums
                        from n4 in nums
                        select new { n1, n2, n3, n4 };

            foreach (var quad in quads)
            {
                float min1 = SingleExtensions.Min(quad.n1, quad.n2, quad.n3, quad.n4);
                float min2 = Math.Min(Math.Min(quad.n1, quad.n2), Math.Min(quad.n3, quad.n4));
                Assert.AreEqual(min2, min1);
            }

            foreach (var quad in quads)
            {
                float max1 = SingleExtensions.Max(quad.n1, quad.n2, quad.n3, quad.n4);
                float max2 = Math.Max(Math.Max(quad.n1, quad.n2), Math.Max(quad.n3, quad.n4));
                Assert.AreEqual(max2, max1);
            }
        }

        private void SingleExtensions_IsNumber()
        {
            float zero = 0;

            float[] arr = new float[] { 0 / zero, 1 / zero, -1 / zero, Single.NaN, 
                                        Single.NegativeInfinity, Single.PositiveInfinity, 
                                        Single.MinValue, Single.MaxValue, 
                                        -1.2f, 0, 1.3f };
            bool[] expected = new bool[] { false, false, false, false, 
                                           false, false, 
                                           true, true, 
                                           true, true, true };

            for (int i = 0; i < arr.Length; i++)
            {
                bool exp = expected[i];
                bool val = arr[i].IsNumber();
                Assert.AreEqual(exp, val);
            }
        }

        private void SingleExtensions_Fraction()
        {
            float[] input = new float[] { -3.6f, -0.4f, 0, 0.2f, 1.3f };
            float[] expected = new float[] { -0.6f, -0.4f, 0, 0.2f, 0.3f };

            for (int i = 0; i < input.Length; i++)
            {
                float result = input[i].Fraction();
                Assert.IsTrue(expected[i].IsAlmostRelativeEquals(result, 1e-7f));
            }
        }

        private void SingleExtensions_Limit()
        {
            Assert.AreEqual(0.3f, SingleExtensions.Limit(0.3f, 0.1f, 0.4f));
            Assert.AreEqual(0.1f, SingleExtensions.Limit(-0.1f, 0.1f, 0.4f));
            Assert.AreEqual(0.4f, SingleExtensions.Limit(0.5f, 0.1f, 0.4f));
            Assert.AreEqual(-0.3f, SingleExtensions.Limit(-0.3f, -0.5f, -0.1f));
            Assert.AreEqual(-0.1f, SingleExtensions.Limit(1.0f, -0.5f, -0.1f));
            Assert.AreEqual(-0.5f, SingleExtensions.Limit(-1.0f, -0.5f, -0.1f));
        }

        private void SingleExtensions_InRange()
        {
            Assert.AreEqual(true, SingleExtensions.InRange(0.3f, 0.1f, 0.4f));
            Assert.AreEqual(true, SingleExtensions.InRange(0.1f, 0.1f, 0.4f));
            Assert.AreEqual(false, SingleExtensions.InRange(-0.3f, 0.1f, 0.4f));
            Assert.AreEqual(false, SingleExtensions.InRange(0.5f, 0.1f, 0.4f));
            Assert.AreEqual(true, SingleExtensions.InRange(-0.3f, -0.5f, -0.1f));
            Assert.AreEqual(false, SingleExtensions.InRange(1.0f, -0.5f, -0.1f));
            Assert.AreEqual(false, SingleExtensions.InRange(-1.0f, -0.5f, -0.1f));
        }
    }
}
